package com.lap.auth.adapter.driving.ports;

import com.fasterxml.jackson.core.type.TypeReference;
import com.lap.auth.shared.ports.Ip2AddressService;
import com.lap.auth.shared.tools.IpRound;
import com.lap.framework.common.tool.JsonUtil;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import java.util.Map;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Slf4j
@RequiredArgsConstructor
@Service
public class Ip2AddressServiceImpl implements Ip2AddressService {

  private static final String NATIVE_ADDRESS = "本地网(01)";
  private static final String LOCAL_ADDRESS = "局域网(01)";
  private static final String UNKNOWN = "未知地址";
  private static final Set<String> NATIVE_IPS = Set.of("localhost", "127.0.0.1", "::1");

  @Qualifier("ipRestTemplate")
  private final RestTemplate restTemplate;

  @Value("${ip.url:https://whois.pconline.com.cn/ipJson.jsp?json=true&ip={ip}}")
  private String url;

  @Override
  public String getAddress(String ip) {
    if (StringUtils.isBlank(ip)) {
      return UNKNOWN;
    }

    if (NATIVE_IPS.contains(ip)) {
      return NATIVE_ADDRESS;
    }

    if (IpRound.validIp(ip)) {
      return LOCAL_ADDRESS;
    }

    try {
      return callRemote(ip);
    } catch (Exception e) {
      log.warn("Remote IP query failed, message:{}", e.getLocalizedMessage());
    }
    return UNKNOWN;
  }

  @CircuitBreaker(name = "authBreaker", fallbackMethod = "fallback")
  public String callRemote(String ip) {
    String resultJson = restTemplate.getForObject(url, String.class, ip);
    Map<String, Object> map = JsonUtil.toObj(resultJson, new TypeReference<>() {});

    if (map != null) {
      Object addrObj = map.get("addr");
      if (addrObj instanceof String addrStr && StringUtils.isNotBlank(addrStr)) {
        return addrStr;
      }
    }
    return UNKNOWN;
  }

  public String fallback(String ip, Throwable e) {
    log.warn("CircuitBreaker triggered for IP: {},{}", ip, e.getLocalizedMessage());
    return UNKNOWN;
  }
}
